package cn.wenhaha.job;

import cn.wenhaha.common.bean.JobStartEvent;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 定时任务工具类
 * 
 * @author wyndem
 *
 */
@Component
public class ScheduleUtils
{
    private static final Logger LOG = LoggerFactory.getLogger(ScheduleUtils.class);
    private ApplicationContext applicationContext;
    @Resource
    private  Scheduler scheduler;
    private ConfigurableListableBeanFactory factory;

    public ScheduleUtils(ApplicationContext applicationContext) {
        this.applicationContext=applicationContext;
        factory = ((ConfigurableApplicationContext)applicationContext).getBeanFactory();
    }

    @EventListener({JobStartEvent.class})
    @Order(-1)
    public void run() throws Exception {
        LOG.info("开始加载定时任务...");
        scheduler.clear();
        ScheduleDynamicUtil.scheduler=scheduler;
        Map<String, WynJobBean> quartzJobBeanMap = applicationContext.getBeansOfType(WynJobBean.class);
        List<WynJobInfo> wynJobInfos = new ArrayList<>();
        // 如果标识了JOb的任务类都会被加载
        quartzJobBeanMap.forEach((k,v)->{
            Job annotation = v.getClass().getAnnotation(Job.class);
            if (annotation==null ||  !annotation.enable()){
                return;
            }
            String cron = annotation.corn();
            long l = annotation.jobId();
            if (l==0){
                l=v.hashCode();
            }
            WynJobInfo wynJobInfo = new WynJobInfo().setJob(v).setJobId(l)
                    .setJobGroup(annotation.group()).setCronExpression(cron);
            wynJobInfos.add(wynJobInfo);
        });
        createScheduleJob(wynJobInfos);
    }


    /**
     * 创建定时任务
     */
    public  void createScheduleJob( List<WynJobInfo>  jobInfoList) {
        jobInfoList.forEach(job->{
            try {
                createScheduleJob(job);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        });

    }


    public  void createScheduleJob(WynJobInfo  job) throws SchedulerException {

        // 构建job信息
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        JobDetail jobDetail = JobBuilder.newJob(job.getJob().getClass()).withIdentity(getJobKey(jobId, jobGroup)).build();
        factory.destroyBean(job.getJob());
        // 表达式调度构建器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        cronScheduleBuilder=cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();

        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
                .withSchedule(cronScheduleBuilder).build();

        // 放入参数，运行时的方法可以获取
//        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

        // 判断是否存在
        if (scheduler.checkExists(getJobKey(jobId, jobGroup)))
        {
            // 防止创建时存在数据问题 先移除，然后在执行创建操作
            scheduler.deleteJob(getJobKey(jobId, jobGroup));
        }

        scheduler.scheduleJob(jobDetail, trigger);

    }


    /**
     * 构建任务触发对象
     */
    public static TriggerKey getTriggerKey(Long jobId, String jobGroup)
    {
        return TriggerKey.triggerKey( jobId.toString(), jobGroup);
    }

    /**
     * 构建任务键对象
     */
    public static JobKey getJobKey(Long jobId, String jobGroup)
    {
        return JobKey.jobKey( jobId.toString(), jobGroup);
    }
}
